//
// Created by Zsir on 2025/8/22.
//
#include "TcpConnection.h"
#include "EventLoop.h"
#include <sys/socket.h>
#include <unistd.h>
#include <iostream>

class Socket {
public:
    explicit Socket(int sockfd) : sockfd_(sockfd) {}
    ~Socket() { if (sockfd_ >= 0) close(sockfd_); }
    int fd() const { return sockfd_; }
private:
    int sockfd_;
};

TcpConnection::TcpConnection(EventLoop* loop, int sockfd,
                             const sockaddr_in& localAddr, const sockaddr_in& peerAddr)
    : loop_(loop),
      socket_(new Socket(sockfd)),
      channel_(new Channel(loop, sockfd)),
      localAddr_(localAddr),
      peerAddr_(peerAddr),
      name_(std::to_string(sockfd)) {

    channel_->setReadCallback(std::bind(&TcpConnection::handleRead, this));
    channel_->setWriteCallback(std::bind(&TcpConnection::handleWrite, this));
    channel_->setCloseCallback(std::bind(&TcpConnection::handleClose, this));
    channel_->setErrorCallback(std::bind(&TcpConnection::handleError, this));
}

TcpConnection::~TcpConnection() {
    std::cout << "TcpConnection 析构：[" << name_ << "]" << std::endl;
}

void TcpConnection::connectEstablished() {
    loop_->assertInLoopThread();
    channel_->enableReading();
}

void TcpConnection::connectDestroyed() {
    loop_->assertInLoopThread();
    channel_->disableAll();
    channel_->remove();
}

void TcpConnection::handleRead() {
    char buf[65536];
    ssize_t n = read(channel_->fd(), buf, sizeof(buf));
    if (n > 0) {
        inputBuffer_.assign(buf, n);
        if (messageCallback_) {
            messageCallback_(shared_from_this(), inputBuffer_);
        }
    } else if (n == 0) {
        handleClose();
    } else {
        handleError();
    }
}

void TcpConnection::handleWrite() {
    ssize_t n = write(channel_->fd(), outputBuffer_.data(), outputBuffer_.size());
    if (n > 0) {
        outputBuffer_.erase(0, n);
        if (outputBuffer_.empty()) {
            channel_->disableWriting();
        }
    } else {
        std::cerr << "TcpConnection::handleWrite - 写入失败" << std::endl;
    }
}

void TcpConnection::handleClose() {
    loop_->assertInLoopThread();
    channel_->disableAll();
    if (closeCallback_) {
        closeCallback_(shared_from_this());
    }
}

void TcpConnection::handleError() {
    int err;
    socklen_t errlen = sizeof(err);
    getsockopt(channel_->fd(), SOL_SOCKET, SO_ERROR, &err, &errlen);
    std::cerr << "TcpConnection::handleError - 套接字错误码 = " << err << std::endl;
}

void TcpConnection::send(const std::string& message) {
    if (loop_->isInLoopThread()) {
        sendInLoop(message);
    } else {
        loop_->runInLoop(std::bind(&TcpConnection::sendInLoop, this, message));
    }
}

void TcpConnection::sendInLoop(const std::string& message) {
    loop_->assertInLoopThread();
    ssize_t n = 0;
    if (!channel_->isWriting() && outputBuffer_.empty()) {
        n = write(channel_->fd(), message.data(), message.size());
        if (n < 0) {
            std::cerr << "TcpConnection::sendInLoop - 写入失败" << std::endl;
            return;
        }
    }

    if (static_cast<size_t>(n) < message.size()) {
        outputBuffer_.append(message.data() + n, message.size() - n);
        if (!channel_->isWriting()) {
            channel_->enableWriting();
        }
    }
}

void TcpConnection::shutdown() {
    if (loop_->isInLoopThread()) {
        shutdownInLoop();
    } else {
        loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this));
    }
}

void TcpConnection::shutdownInLoop() {
    loop_->assertInLoopThread();
    if (!channel_->isWriting()) {
        ::shutdown(channel_->fd(), SHUT_WR);
    }
}
